/**
 * Copyright (C) 2010 Cloudfarming <info@cloudfarming.nl>
 *
 * Licensed under the Eclipse Public License - v 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.cloudfarming.client.planning.tactical.wizard.spray;

import nl.cloudfarming.client.planning.tactical.wizard.common.PlandateController;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import javax.swing.JComponent;
import nl.cloudfarming.client.logging.AppLogFactory;
import nl.cloudfarming.client.logging.AppLogger;
import nl.cloudfarming.client.model.CropProtectionTask;
import nl.cloudfarming.client.model.ProductionUnit;
import nl.cloudfarming.client.model.PartField;
import nl.cloudfarming.client.model.Operation;
import nl.cloudfarming.client.planning.PlanAction;
import nl.cloudfarming.client.planning.PlanEventKey;
import nl.cloudfarming.client.planning.tactical.TacticalPlanningModule;
import nl.cloudfarming.client.planning.tactical.TacticalPlanningService;
import nl.cloudfarming.eventbus.BaseGuiEventProducer;
import nl.cloudfarming.eventbus.GuiEvent;
import nl.cloudfarming.eventbus.GuiEventKey;
import org.openide.DialogDisplayer;
import org.openide.WizardDescriptor;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;

// An example action demonstrating how the wizard could be called from within
// your code. You can move the code below wherever you need, or register an action:
// @ActionID(category="...", id="nl.cloudfarming.client.planning.tactical.PlanningWizardAction")
// @ActionRegistration(displayName="Open Planning Wizard")
// @ActionReference(path="Menu/Tools", position=...)
public final class PlanningWizardAction extends PlanAction implements ActionListener {

    private TacticalPlanningService service;
    private WizardDescriptor.Panel[] panels;
    private static final String DISPLAY_NAME = NbBundle.getMessage(TacticalPlanningModule.class, "field_plan.wizard.spray.planning_wizard_action.name");
    private static final String TITLE = NbBundle.getMessage(TacticalPlanningModule.class, "field_plan.wizard.spray.planning_wizard_action.title");
    private static final String OPERATION_NAME = NbBundle.getMessage(TacticalPlanningModule.class, "field_plan.wizard.spray.planning_wizard_action.operation_name");
    private final PlanningEventProducer planningEventProducer = new PlanningEventProducer();
    private static final AppLogger LOG = AppLogFactory.getLogger(PlanningWizardAction.class);
    

    public PlanningWizardAction() {
        putValue(NAME, DISPLAY_NAME);
    }

    @Override
    public void actionPerformed(ActionEvent e) {

        WizardDescriptor wizardDescriptor = new WizardDescriptor(getPanels());
        // {0} will be replaced by WizardDesriptor.Panel.getComponent().getName()
        wizardDescriptor.setTitleFormat(new MessageFormat("{0}"));
        wizardDescriptor.setTitle(TITLE);
        Dialog dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor);
        dialog.setVisible(true);
        dialog.toFront();
        boolean cancelled = wizardDescriptor.getValue() != WizardDescriptor.FINISH_OPTION;
        if (!cancelled) {
            Operation operation;
            try {
                operation = saveWizardContent(wizardDescriptor);
                planningEventProducer.triggerEvent(new OperationPlanEvent(operation, PlanEventKey.NEW_OPERATION));
            } catch (CropProtectionNotFoundException ex) {
                LOG.error(ex.getMessage(), ex);
            } catch (ProductionUnitNotFoundException ex) {
                LOG.error(ex.getMessage(), ex);
            } catch (ParseException ex) {
                LOG.error(ex.getMessage(), ex);
            }
        }
    }

    /**
     * Method which saves the data in the wizard
     * @param wizardDescriptor
     * @return 
     */
    protected Operation saveWizardContent(WizardDescriptor wizardDescriptor) throws ParseException, ProductionUnitNotFoundException, CropProtectionNotFoundException {
        ArrayList<CropProtectionTask> selectedCropProtections =  (ArrayList<CropProtectionTask>) wizardDescriptor.getProperty(OperationController.CROP_PROTECTION_TASK_PROPERTIES);
        Date planDate = (Date) wizardDescriptor.getProperty(PlandateController.PLANDATE);

        ProductionUnit productionUnit = Utilities.actionsGlobalContext().lookup(ProductionUnit.class);

        if (productionUnit != null) {
            Operation operation = null;
            operation = getService().createOperation(selectedCropProtections.get(0).getOperation());
            for (PartField partField : productionUnit.getPartFields()) {
                if (selectedCropProtections != null) {
                    for(CropProtectionTask cropProtectionTask : selectedCropProtections) {
                        cropProtectionTask.setPlanDate(planDate);
                        cropProtectionTask.setPartField(partField);
                        operation.setName(OPERATION_NAME);
                        cropProtectionTask.setOperation(operation);
                        getService().createCropProtectionTask(cropProtectionTask);
                    }
                } else{
                    throw new CropProtectionNotFoundException("CropProtection could not be found when trying to save wizard data");
                }
            }

            return operation;
        } else {
            throw new ProductionUnitNotFoundException("ProductionUnit not found while trying to save wizard data");
        }

    }

    /**
     * Initialize panels representing individual wizard's steps and sets
     * various properties for them influencing wizard appearance.
     */
    private WizardDescriptor.Panel[] getPanels() {
        if (panels == null) {
            panels = new WizardDescriptor.Panel[]{
                new PlandateController(),
                new CropProtectionController(),
                new OperationController(),
                new SummaryController()
            };
            String[] steps = new String[panels.length];
            for (int i = 0; i < panels.length; i++) {
                Component c = panels[i].getComponent();
                // Default step name to component name of panel. Mainly useful
                // for getting the name of the target chooser to appear in the
                // list of steps.
                steps[i] = c.getName();
                if (c instanceof JComponent) { // assume Swing components
                    JComponent jc = (JComponent) c;
                    // Sets step number of a component
                    
                    jc.putClientProperty("WizardPanel_contentSelectedIndex", Integer.valueOf(i));
                    // Sets steps names for a panel
                    jc.putClientProperty("WizardPanel_contentData", steps);
                    // Turn on subtitle creation on each step
                    jc.putClientProperty("WizardPanel_autoWizardStyle", Boolean.TRUE);
                    // Show steps on the left side with the image on the background
                    jc.putClientProperty("WizardPanel_contentDisplayed", Boolean.TRUE);
                    // Turn on numbering of all steps
                    jc.putClientProperty("WizardPanel_contentNumbered", Boolean.TRUE);
                }
            }
        }
        return panels;
    }

    /**
     * Return service for tactical planning
     * @return The service for tactical planning
     */
    protected TacticalPlanningService getService() {
        if (service == null) {
            service = new TacticalPlanningService();
        }
        return service;
    }

    /**
     * Set service for tactical planning
     * @param service Service to set
     */
    public void setService(TacticalPlanningService service) {
        this.service = service;
    }

    private class OperationPlanEvent implements GuiEvent<Operation> {

        private final Operation operation;
        private final PlanEventKey key;

        /**
         * Constructor
         * @param fieldPlan: the fieldplan for which the event is triggered
         * @param key: the event key. Which action has been done to trigger this event. 
         */
        public OperationPlanEvent(Operation operation, PlanEventKey key) {
            this.operation = operation;
            this.key = key;
        }

        @Override
        public GuiEventKey getKey() {
            return key;
        }

        @Override
        public Operation getContent() {
            return operation;
        }
    }

    private class PlanningEventProducer extends BaseGuiEventProducer {

        public PlanningEventProducer() {
            super(PlanEventKey.class);
        }
    }
}
